{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e208df66",
   "metadata": {},
   "source": [
    "# 红烧鱼变清蒸鱼(PIL图像处理)\n",
    "## 学习目标\n",
    "计算机视觉任务包括显示、裁剪、翻转、旋转、图像分割、分类、影像复原、图像识别、图像生成。图像处理技术不仅广泛应用于工业、医疗、安全监控等多个领域，也逐渐成为创意设计和个性化表达的重要工具。Python凭借其丰富的库资源，如Pillow，成为了进行图像处理的热门选择。本实践项目旨在通过Python Pillow（PIL）库，让学生掌握基础的图像处理技巧，并结合中文元素，创作出具有创意的文字图片，以此加深对图像处理技术的理解和应用能力。\n",
    "\n",
    "Python 图像处理库完成如下的实验：\n",
    "- 绘制一张图片\n",
    "- 灰度图像\n",
    "- 量化图像和颜色通道\n",
    "- 把图像转换为Numpy数组\n",
    "\n",
    "### 实践步骤\n",
    "1. 环境准备\n",
    "- 安装Python环境：确保安装了Python 3.x版本。\n",
    "- 安装Pillow库：通过命令行执行pip install Pillow安装。\n",
    "2. 图像基础操作\n",
    "- 加载图像：使用Image.open()方法打开一张图片。\n",
    "- 显示图像：利用imshow()函数（需导入matplotlib库）显示图像。\n",
    "- 保存修改后的图像：使用Image.save()方法保存处理后的图像。\n",
    "3. 图像特效探索\n",
    "- 灰度转换：将彩色图像转换为灰度图像，使用Image.convert('L')方法。\n",
    "- 色彩量化与通道操作：了解并尝试调整图像的色彩量化及单独处理RGB通道。\n",
    "- 图像变换：实践图像的旋转(rotate()方法)、翻转(transpose()方法)和裁剪(crop()方法)。\n",
    "4. NumPy与图像处理\n",
    "- 图像转数组：使用np.array()将Pillow图像对象转换为NumPy数组。\n",
    "- 数组操作：在NumPy数组上进行数值处理，如亮度调整、滤波等。\n",
    "- 数组转图像：将处理后的数组转换回Pillow图像对象，展示效果。\n",
    "### 项目成果展示\n",
    "- 创作至少三张不同风格的中文艺术字图片，每张图片需包含不同的文字内容、字体风格及至少两种图像处理特效。\n",
    "- 编写一份简短的报告，介绍每张图片的设计思路、使用的图像处理技术及遇到的挑战与解决方案。\n",
    "### 指导建议\n",
    "- 实践为主：鼓励学生动手尝试，通过实际操作来理解每个概念和方法。\n",
    "- 创意激发：引导学生思考如何将所学技术与个人兴趣或文化元素结合，创作独特作品。\n",
    "- 问题解决：遇到技术难题时，先查阅官方文档或在线资源，培养自主解决问题的能力。\n",
    "通过本项目，学生不仅能学会Python在图像处理领域的基本技能，还能激发创新思维，为将来深入学习计算机视觉和人工智能打下坚实的基础。\n",
    "\n",
    "\n",
    "### 图片文件和路径\n",
    "图像作为一个文件存储在电脑中。我们定义这个目录下的文件的文件名是`my_image`。文件名由两部分组成: 文件名和扩展名，中间用一个句号(.)分隔.扩展指定 Image 的格式。有两种流行的图像格式: `.JPG``.Jpeg``.png` 这些文件类型使得处理图像更加简单。例如，它压缩图像，在驱动器上占用较少的空间来存储图像。例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d23c6d15",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 其中./是文件路径<表示当前路径>，fish是文件名，`.png`是文件后缀\n",
    "\n",
    "my_image = \"./fish.png\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37b373e6",
   "metadata": {},
   "source": [
    "### 用Python加载图像\n",
    "\n",
    "Pillow (PIL)库是一个用于在 Python 中加载图像的流行库,此外，许多其他库，如: “ Keras”和“ 。`Image` PIL模块提供了从文件系统加载图像并进行图像处理的功能，让我们从 `PIL`导入它并我们将使用它。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f71df02c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入图像处理库\n",
    "from PIL import Image\n",
    "# 打开图片，并创建一个image对象\n",
    "image = Image.open(my_image) \n",
    "#查看对象类型\n",
    "print(type(image))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85411572",
   "metadata": {},
   "source": [
    "### 用matplotlib画图"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3efd5b97",
   "metadata": {},
   "source": [
    "数据可视化领域中最常用和最强大的工具之一，广泛应用于数据分析、科学研究、工程绘图等领域。matplotlib 提供了丰富的绘图功能，可以生成高质量的图表，包括线图、散点图、柱状图、饼图、直方图、等高线图等。本案例中使用`matplotlib`库中的`imshow`方法展示图片，查看图片属性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "36824820",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# figsize=(10, 10) 表示创建一个宽度为 10 英寸、高度为 10 英寸的正方形图形。\n",
    "plt.figure(figsize=(10,10))\n",
    "\n",
    "# 显示之前加载的image对象的图片\n",
    "plt.imshow(image)\n",
    "plt.title('red fish is now')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94266f80",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看图像的属性\n",
    "print(\"图像类型、图像大小、图像格式：\")\n",
    "print(image.mode)\n",
    "print(image.format)\n",
    "print(image.size)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9580d0ce",
   "metadata": {},
   "source": [
    "`Image.open`方法不将图像数据加载到计算机内存中，`PIL`对象`load`方法,读取文件内容，对其进行解码，并将图像加载到内存中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a593aef",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载图片，打印对象属性\n",
    "image_load = image.load()\n",
    "print(image_load)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff9ea8a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取图像的宽度和高度\n",
    "width, height = image.size\n",
    "\n",
    "# 访问和修改像素值\n",
    "for x in range(width):\n",
    "    for y in range(height):\n",
    "        # 获取当前像素的 RGB 值\n",
    "        r, g, b = image_load[x, y]\n",
    "        \n",
    "        # 修改像素值（例如，将红色通道的值增加 150）\n",
    "        image_load[x, y] = (r + 150, g, b)\n",
    "\n",
    "# 保存修改后的图像，并查看\n",
    "image.save('modified_fish.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "629e98f5",
   "metadata": {},
   "source": [
    "## 灰度图片、量化、颜色通道处理"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbbe8351",
   "metadata": {},
   "source": [
    "### 灰度图片"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58acce33",
   "metadata": {},
   "source": [
    "`ImageOps`模块包含了几种现成的图像处理操作。该模块有些实验性，大多数操作仅适用于灰度和/或RGB图像。灰度图像的像素值表示该像素的光量或强度。浅灰色具有高亮度，而深灰色则亮度较低，即白色具有最高亮度，黑色具有最低亮度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94de0753",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载 ImageOps方法\n",
    "from PIL import ImageOps\n",
    "\n",
    "# 将彩色图像转换为灰度图像\n",
    "image_gray = ImageOps.grayscale(image)\n",
    "mode = image_gray.mode\n",
    "print(f'灰度图像的模式: {mode}')\n",
    "image_gray.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4052fef5",
   "metadata": {},
   "source": [
    "### 量化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c7163b2",
   "metadata": {},
   "source": [
    "图像的量化是指图像中任意给定像素可以具有的唯一强度值的数量。对于灰度图像而言，这意味着不同灰度级别的数量。大多数图像有256个不同的灰度级。使用quantize方法减少灰度级别。让我们反复将灰度级数量减半并观察会发生什么："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a8263e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#图片变灰\n",
    "image_quantized = image_gray.quantize(256//2)\n",
    "# 获取量化后图像的模式\n",
    "mode = image_quantized.mode\n",
    "print(f'量化后图像的模式: {mode}')\n",
    "image_gray.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b946ab5f",
   "metadata": {},
   "source": [
    "### 颜色通道\n",
    "\n",
    "通过 get_concat_h() 函数，将图片水平拼接，并设置背景颜色，得到一个三通道的图片，通过颜色通道的像素值不同，可以得到不同颜色通道的图片，并和原始图像镜像比较查看效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ccf8768b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 让我们定义一个 helper 函数拼接两个图像\n",
    "def get_concat_h(im1, im2):\n",
    "    #https://note.nkmk.me/en/python-pillow-concat-images/\n",
    "    dst = Image.new('RGB', (im1.width + im2.width, im1.height))\n",
    "    dst.paste(im1, (0, 0))\n",
    "    dst.paste(im2, (im1.width, 0))\n",
    "    return dst"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d98cd1a9",
   "metadata": {},
   "source": [
    "通过3~8随机数，2**n表示2的n次幂，获得不同灰度级别状态下的图片级别，并和源图进行比较。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89b3253b",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "#get_concat_h(image_gray,  image_gray.quantize(256//2)).show(title=\"Lena\") \n",
    "for n in range(3,8):\n",
    "    plt.figure(figsize=(10,10))\n",
    "\n",
    "    plt.imshow(get_concat_h(image_gray,  image_gray.quantize(256//2**n)))  #灰度值除以2，并将其与原始图像进行比较。\n",
    "    plt.title(\"256 Quantization Levels  left vs {}  Quantization Levels right\".format(256//2**n))\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84d548fd",
   "metadata": {},
   "source": [
    "### 查看不同通道"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe1bbdc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取不同的RGB颜色通道，并将它们分配给变量red（红色）、green（绿色）和blue（蓝色）\n",
    "red,green,blue = image.split()\n",
    "#将红色通道旁边的彩色图像绘制成灰度图，我们可以看到红色区域具有更高的亮度值。\n",
    "get_concat_h(image,red) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ab5e46f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将蓝色通道旁边的彩色图像绘制成灰度图，我们可以看到红色区域具有更高的亮度值。\n",
    "get_concat_h(image, blue)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d93b05e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将绿色通道旁边的彩色图像绘制成灰度图，我们可以看到红色区域具有更高的亮度值。\n",
    "get_concat_h(image, green)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bee6afc2",
   "metadata": {},
   "source": [
    "### PIL图像转换为NumPy数组"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aca954f0",
   "metadata": {},
   "source": [
    "NumPy 是一个 Python 库，允许您使用多维数组和矩阵。我们可以将 PIL 图像转换为 NumPy 数组。我们使用来自 NumPy 的 asarray()或 array函数将 PIL 图像转换为 NumPy 数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c4eadca",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np \n",
    "array = np.asarray(image)\n",
    "print(type(array))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbaafb5c",
   "metadata": {},
   "source": [
    " `np.asarray` 将原始图像转换为一个 numpy 数组。通常，我们不想直接操作图像，而是创建一个要操作的图像副本。`np.rray` 方法创建图像的一个新副本，这样原始副本将保持不变。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a397569a",
   "metadata": {},
   "source": [
    "`numpy.array`对象`shape`能返回一个tuple `(rows,columns,colors)`，表达它的尺寸，第一个元素给出图像的行数或高度，第二个元素是图像的列数或宽度。最后一个元素是彩色通道的数量。\n",
    "颜色轴上的每个元素对应数值`(R,G,B)` ，通过输出array 我们可以看到intensity values,是0~255的数字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2bd70048",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 打印array对象数据组\n",
    "print(array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "363a095b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 查看数组边界\n",
    "print(array.min()) #minimum intensity value of the array\n",
    "print(array.max())#maximum intensity value of the array"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38b51ccb",
   "metadata": {},
   "source": [
    "### 课程贡献者\n",
    "\n",
    "- 沈妍瑜\n",
    "- topshare<审核>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
